package no.cicero.testframework.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;

public class Config {
	private boolean useHeader = true;
	public boolean isUseHeader() {
		return useHeader;
	}
	public void setUseHeader(boolean useHeader) {
		this.useHeader = useHeader;
	}

    private boolean testStructureOnly = false;
    public boolean isTestStructureOnly() { return testStructureOnly; }
    public void setTestStructureOnly(boolean testStructureOnly) { this.testStructureOnly = testStructureOnly; }

    private URL targetUrl;
    public URL getTargetUrl() { return targetUrl; }
    public void setTargetUrl(URL targetUrl) { this.targetUrl = targetUrl; }

    private String namespace;
    public String getNamespace() { return namespace; }
    public void setNamespace(String namespace) { this.namespace = namespace; }

    private String namespacePrefix = "ws";
    public String getNamespacePrefix() { return namespacePrefix; }
    public void setNamespacePrefix(String namespacePrefix) { this.namespacePrefix = namespacePrefix; }

    private File outputLocation = new File("./");
    public File getOutputLocation() { return outputLocation; }
    public void setOutputLocation(File outputLocation) { this.outputLocation = outputLocation; }

    private File templateLocation = new File("./");
    public File getTemplateLocation() { return templateLocation; }
    public void setTemplateLocation(File templateLocation) { this.templateLocation = templateLocation; }

    private File useCaseLocation = new File("./");
    public File getUseCaseLocation() { return useCaseLocation; }
    public void setUseCaseLocation(File usecaseLocation) { this.useCaseLocation = usecaseLocation; }

    private File testCaseLocation = new File("./");
    public File getTestCaseLocation() { return testCaseLocation; }
    public void setTestCaseLocation(File testcaseLocation) { this.testCaseLocation = testcaseLocation; }

	private Collection<Pattern> useCaseFilters;
	public Collection<Pattern> getUseCaseFilters() { return useCaseFilters; }
	public void setUseCaseFilters(Collection<Pattern> useCaseFilters) { this.useCaseFilters = useCaseFilters; }
	
	private Collection<Pattern> testCaseFilters;
	public Collection<Pattern> getTestCaseFilters() { return testCaseFilters; }
	public void setTestCaseFilters(Collection<Pattern> testCaseFilters) { this.testCaseFilters = testCaseFilters; }

	private int numberOfUsers = 1;
	public int getNumberOfUsers() {return numberOfUsers;}
	public void setNumberOfUsers(int numberOfUsers) {this.numberOfUsers = numberOfUsers;}

	private String user;
	public String getUser() { return user; }
	public void setUser(String user) { this.user = user; }

	private String password;
	public String getPassword() { return password; }
	public void setPassword(String password) { this.password = password; }

	private Map<String, String> params = new HashMap<String, String>();
	public Map<String, String> getParams() { return params; }
	public void setParams(Map<String, String> params) { this.params = params; }

	private List<String> useCaseNames ;
	public List<String> getUseCaseNames() {
        if(useCaseNames == null)
            useCaseNames = readUseCaseNames();
        return useCaseNames;
    }
	public void setUseCaseNames(List<String> useCaseNames) { this.useCaseNames = useCaseNames; }

	public boolean matchesTestCase(String testCaseName){
		return testCaseFilters == null || testCaseFilters.isEmpty() || matches(testCaseName, testCaseFilters);
	}

	public boolean matchesUseCase(String useCaseName){
		return useCaseFilters == null || useCaseFilters.isEmpty() || matches(useCaseName, useCaseFilters);
	}

	private boolean matches(String str, Collection<Pattern> patterns){
		for(Pattern p: patterns){
			if(p.matcher(str).matches())
				return true;
		}
		return false;
	}


	public Config() {
    }

    public Config(String configPath) throws FileNotFoundException, IOException {
        File sourceFile = new File(configPath);

        Properties properties = new Properties();
        FileInputStream inputStream = new FileInputStream(sourceFile);
        properties.load(inputStream);

		testStructureOnly = Boolean.parseBoolean(properties.getProperty("testStructureOnly", "false"));

        targetUrl = new URL(properties.getProperty("targetUrl"));
        namespace = properties.getProperty("namespace");
        namespacePrefix = properties.getProperty("namespacePrefix", "ws");

        outputLocation = new File(properties.getProperty("outputLocation", "./"));
        templateLocation = new File(properties.getProperty("templateLocation", "./"));
        useCaseLocation = new File(properties.getProperty("useCaseLocation", "./"));
        testCaseLocation = new File(properties.getProperty("testCaseLocation", "./"));

		useCaseFilters = getFilter(properties, "useCaseFilter");
		testCaseFilters = getFilter(properties, "testCaseFilter");

		numberOfUsers = Integer.parseInt(properties.getProperty("numberOfUsers", "1"));

		useHeader = Boolean.parseBoolean(properties.getProperty("useHeader", "true"));
		
		String security = properties.getProperty("security");
		if(security != null && security.length() > 0){
			String[] securityParts = security.split(":");
			user = securityParts[0];
			if(securityParts.length > 1)
				password = securityParts[1];
			else
				password = "";
		}

		String paramsStr = properties.getProperty("params");
		if(paramsStr != null){
			String[] paramsPairs = paramsStr.split(";");
			for(String paramsPair: paramsPairs){
				String[] keyValue = paramsPair.split(":");
				String key = keyValue[0];
				String value = (keyValue.length > 1)? keyValue[1]: "";
				params.put(key, value);
			}
		}		
    }

	public Config(boolean testStructureOnly, URL targetUrl, String namespace, String namespacePrefix
				  , File outputLocation, File templateLocation
				  , File useCaseLocation, File testCaseLocation
				  , Collection<Pattern> useCaseFilters, Collection<Pattern> testCaseFilters
				  , String user, String password, Map<String, String> params)
	{
		this.testStructureOnly = testStructureOnly;
		this.targetUrl = targetUrl;
		this.namespace = namespace;
		this.namespacePrefix = namespacePrefix;
		this.outputLocation = outputLocation;
		this.templateLocation = templateLocation;
		this.useCaseLocation = useCaseLocation;
		this.testCaseLocation = testCaseLocation;
		this.useCaseFilters = useCaseFilters;
		this.testCaseFilters = testCaseFilters;
		this.user = user;
		this.password = password;
		this.params = params;
		this.useHeader = true;
	}

	/**
	 * This constructor creates config for CFP 5.0, i.e. useHeader = false and no user, password and params
	 * */
	public Config(boolean testStructureOnly, URL targetUrl, String namespace, String namespacePrefix
				  , File outputLocation, File templateLocation
				  , File useCaseLocation, File testCaseLocation
				  , Collection<Pattern> useCaseFilters, Collection<Pattern> testCaseFilters)
	{
		this.testStructureOnly = testStructureOnly;
		this.targetUrl = targetUrl;
		this.namespace = namespace;
		this.namespacePrefix = namespacePrefix;
		this.outputLocation = outputLocation;
		this.templateLocation = templateLocation;
		this.useCaseLocation = useCaseLocation;
		this.testCaseLocation = testCaseLocation;
		this.useCaseFilters = useCaseFilters;
		this.testCaseFilters = testCaseFilters;
		this.useHeader = false;
	}

	private Collection<Pattern> getFilter(Properties properties, String filterName){
		Collection<Pattern> ret = new ArrayList<Pattern>();

		String filtersSet = properties.getProperty(filterName);
		if(filtersSet != null && filtersSet.length() == 0)
			filtersSet = null;

		if(filtersSet != null){
			String[] filters = filtersSet.split(";");
			for(String filter: filters)
				ret.add(Pattern.compile(filter));
		}

		return ret;
	}

    private List<String> readUseCaseNames () {
        if (useCaseLocation.isDirectory()) {
            TreeSet<String> filesSet = new TreeSet<String>();
            for(File file: useCaseLocation.listFiles()){
                if(file.isFile() && matchesUseCase(file.getName()))
                    filesSet.add(file.getName());
            }
			return new ArrayList<String>(filesSet);

        } else {
            throw new RuntimeException("Can't open use cases " + useCaseLocation + " directory");
        }
    }
}

